/*
 * Copyright (c) 2010 CCX(China) Co.,Ltd. All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * CCX(China) Co.,Ltd. ("Confidential Information").
 * It may not be copied or reproduced in any manner without the express 
 * written permission of CCX(China) Co.,Ltd.
 *
 * Author: zhaosj
 * Date: 2010-10-19 上午10:46:13
 */
package com.ma.business;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Set;
import java.util.Map.Entry;

import com.ma.vo.MaStock;
import com.ma.vo.TradeParameter;
import com.util.ConnUtil;

/**
 * @author zhaosj
 * 
 */
public class CalculateMA {

	/**
	 * 从聚源数据库获取股票的内部编码、证券代码、收盘价、交易日期
	 * 
	 * @return 股票map
	 */
	public HashMap<Long, ArrayList<MaStock>> getStockInfo(TradeParameter tp) {

		HashMap<Long, ArrayList<MaStock>> map = new HashMap<Long, ArrayList<MaStock>>();
		try {

			Connection con = ConnUtil.getConnection("jyOracle");
			String dateStart = tp.getDateStart();
			String dateEnd = tp.getDateEnd();
			Date startDate = new SimpleDateFormat("yyyy-MM-dd").parse(dateStart);
			Date endDate = new SimpleDateFormat("yyyy-MM-dd").parse(dateEnd);

			// 获取沪深股票的内部代码
			String sql01 = "select s.innercode from jydb.secumain s " + " where (substr(s.secucode,1,2) = '00' and s.secumarket = 90) "
					+ " or (substr(s.secucode,1,2) = '60' and s.secumarket = 83) order by innercode";

			PreparedStatement pst1 = con.prepareStatement(sql01);
			ResultSet rs1 = pst1.executeQuery();

			// 根据内部代码获取股票历史交易行情
			String sql02 = "select q.innercode, q.tradingday, q.closeprice, s.secucode, s.secumarket,"
					+ " row_number() over(partition by q.innercode order by q.tradingday desc) top " + " from jydb.QT_DailyQuote q, jydb.secumain s "
					+ " where q.closeprice > 0 and q.innercode = s.innercode " + " and ((substr(s.secucode,1,2) = '00' and s.secumarket = 90) or"
					+ " (substr(s.secucode,1,2) = '60' and s.secumarket = 83))" + " and q.innercode = ?" + " and tradingday >= ? and tradingday <= ?"
					+ " order by tradingday desc";

			ResultSet rs2 = null;

			Long innercode = 0L;
			ArrayList<MaStock> maStockList = null;
			PreparedStatement pst2 = con.prepareStatement(sql02);

			while (rs1.next()) {

				maStockList = new ArrayList<MaStock>();
				innercode = rs1.getLong(1);

				pst2.setLong(1, innercode);
				pst2.setDate(2, new java.sql.Date(startDate.getTime()));
				pst2.setDate(3, new java.sql.Date(endDate.getTime()));
				rs2 = pst2.executeQuery();

				System.out.println("get stock quote, innercode : " + innercode);

				MaStock ms = null;
				while (rs2.next()) {
					ms = new MaStock();
					ms.setInnercode(innercode);
					ms.setCloseprice(rs2.getDouble("closeprice"));
					ms.setTradingday(rs2.getDate("tradingday"));
					ms.setSecucode(rs2.getString("secucode"));

					maStockList.add(ms);
				}

				map.put(innercode, maStockList);

			}
			rs2.close();
			pst2.close();

			rs1.close();
			pst1.close();
			con.close();

		} catch (Exception e) {

			e.printStackTrace();
		}

		return map;
	}

	/**
	 * 计算股票均线
	 * 
	 * @param map
	 * @return
	 */
	public ArrayList<MaStock> calculateMa(HashMap<Long, ArrayList<MaStock>> map, TradeParameter tp) {

		ArrayList<MaStock> list = new ArrayList<MaStock>();
		try {

			int Mbs = tp.getBs(); // 买入天数-短线
			int Mbl = tp.getBl(); // 买入天数-长线
			int Mss = tp.getSs(); // 卖出天数-短线
			int Msl = tp.getSl(); // 卖出天数-长线

			Set<Entry<Long, ArrayList<MaStock>>> set = map.entrySet();
			for (Entry<Long, ArrayList<MaStock>> entry : set) {

				Long innercode = entry.getKey();

				ArrayList<MaStock> valueList = entry.getValue();
				System.out.println("Calculate MA, innercode : " + innercode);

				if (valueList.size() > 0) {
					for (int i = 0; i < valueList.size(); i++) // 倒序遍历该股票的交易日期
					{
						MaStock mas = new MaStock();
						MaStock ms = valueList.get(i);
						Date tradingday = ms.getTradingday();
						String secucode = ms.getSecucode();

						double closeprice = ms.getCloseprice();
						double bs = 0.0;
						double bl = 0.0;
						double ss = 0.0;
						double sl = 0.0;

						int remainSize = valueList.size() - i;

						if (remainSize >= Mbs) // 记录多于买入短线天数
						{
							for (int j = 0; j < Mbs; j++) {
								ms = valueList.get(i + j);
								bs += ms.getCloseprice();
							}
							bs /= Mbs;

						}
						if (remainSize >= Mbl) // 记录多于买入长线天数
						{
							for (int j = 0; j < Mbl; j++) {
								ms = valueList.get(i + j);
								bl += ms.getCloseprice();
							}
							bl /= Mbl;
						}
						if (remainSize >= Mss) // 记录多于卖出短线天数
						{
							for (int j = 0; j < Mss; j++) {
								ms = valueList.get(i + j);
								ss += ms.getCloseprice();
							}
							ss /= Mss;
						}
						if (remainSize >= Msl) // 记录多于卖出长线天数
						{
							for (int j = 0; j < Msl; j++) {
								ms = valueList.get(i + j);
								sl += ms.getCloseprice();
							}
							sl /= Msl;
						}

						// 数据插入数据表
						mas.setInnercode(innercode);
						mas.setSecucode(secucode);
						mas.setBs(bs);
						mas.setBl(bl);
						mas.setSs(ss);
						mas.setSl(sl);
						mas.setTradingday(tradingday);
						mas.setCloseprice(closeprice);

						list.add(mas);
					}
				}
			}

		} catch (Exception e) {

			e.printStackTrace();
		}

		return list;
	}

	/**
	 * 插入均线数据
	 * 
	 * @param list
	 */
	public void insertIntoMa(ArrayList<MaStock> list) {
		try {

			Connection con = ConnUtil.getConnection("localOracle");

			// 开始新一轮的统计
			String sql = "insert into ma_stock(id,innercode,secucode,bs,bl,ss,sl,tradingday,closeprice) values(seq_ma_stock.nextval,?,?,?,?,?,?,?,?)";
			PreparedStatement pst = con.prepareStatement(sql);

			for (MaStock ms : list) {

				pst.setLong(1, ms.getInnercode());
				pst.setString(2, ms.getSecucode());
				pst.setDouble(3, ms.getBs());
				pst.setDouble(4, ms.getBl());
				pst.setDouble(5, ms.getSs());
				pst.setDouble(6, ms.getSl());
				pst.setDate(7, (java.sql.Date)ms.getTradingday());
				pst.setDouble(8, ms.getCloseprice());

				System.out.println("Insert MA into db, innercode : " + ms.getInnercode() + " " + ms.getTradingday());
				pst.executeUpdate();
			}

			pst.close();
			con.close();

		} catch (Exception e) {

			e.printStackTrace();
		}

	}

	/**
	 * 清除历史统计数据
	 */
	public void truncateStatisticDate() {

		try {

			Connection con = ConnUtil.getConnection("localOracle");
			PreparedStatement pst = null;

			String sql = "truncate table ma_stock";
			pst = con.prepareStatement(sql);
			pst.executeUpdate();

			sql = "truncate table ma_position";
			pst = con.prepareStatement(sql);
			pst.executeUpdate();

			sql = "truncate table ma_history";
			pst = con.prepareStatement(sql);
			pst.executeUpdate();

			pst.close();
			con.close();

		} catch (Exception e) {

			e.printStackTrace();
		}
	}

	/**
	 * 根据历史行情数据，计算出均线并入库
	 * 
	 * @param tp
	 */
	public void operateStockMa(TradeParameter tp) {

		// 清除历史统计数据
		truncateStatisticDate();

		// 获取股票行情数据
		HashMap<Long, ArrayList<MaStock>> map = getStockInfo(tp);

		// 计算均线值
		ArrayList<MaStock> list = calculateMa(map, tp);

		// 将均线值插入数据库
		insertIntoMa(list);
	}

}
